package com.small.nacos.naming.core;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.small.nacos.common.notify.NotifyCenter;
import com.small.nacos.core.cluster.*;
import com.small.nacos.sys.env.EnvUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * @Author zhoujin
 * @Date 2022/10/31 19:50
 */
@Component("distroMapper")
public class DistroMapper extends MemberChangeListener {

    protected static final Logger LOGGER = LoggerFactory.getLogger(DistroMapper.class);

    //健康服务,不允许修改
    private volatile List<String> healthyList = new ArrayList<>();

    private final ServerMemberManager memberManager;

    public DistroMapper(ServerMemberManager memberManager) {
        this.memberManager = memberManager;
    }

    @PostConstruct
    public void init() {
        NotifyCenter.registerSubscriber(this);
        this.healthyList = MemberUtil.simpleMembers(memberManager.allMembers());
    }

    public boolean responsible(String groupedServiceName) {
        if (healthyList.size() == 0) {
            return true;
        }

        if (EnvUtil.getStandaloneMode()) {
            return true;
        }

        String localAddress = EnvUtil.getLocalAddress();
        int i = healthyList.indexOf(localAddress);
        int index = distroHash(groupedServiceName) % healthyList.size();
        return i == index;
    }

    public String mapSrv(String groupedServiceName) {
        final List<String> servers = healthyList;

        if (CollectionUtils.isEmpty(servers)) {
            return EnvUtil.getLocalAddress();
        }

        try {
            int index = distroHash(groupedServiceName) % servers.size();
            return servers.get(index);
        } catch (Throwable e) {
            return EnvUtil.getLocalAddress();
        }
    }

    private int distroHash(String serviceName) {
        return Math.abs(serviceName.hashCode() % Integer.MAX_VALUE);
    }


    @Override
    public void onEvent(MembersChangeEvent event) {
        List<String> list = MemberUtil.simpleMembers(MemberUtil.selectTargetMembers(event.getMembers(),
                member -> NodeState.UP.equals(member.getState()) || NodeState.SUSPICIOUS.equals(member.getState())));
        Collections.sort(list);
        Collection<String> old = healthyList;
        //更新（健康实例和可疑实例） 并且设置为不可更改
        healthyList = Collections.unmodifiableList(list);
        LOGGER.info("[NACOS-DISTRO] healthy server list changed, old: {}, new: {}", old, healthyList);
    }
}
